package com.serviceprovider.business.module.order.controller;

//~--- non-JDK imports --------------------------------------------------------

import com.serviceprovider.business.module.admin.user.services.dao.interfaces.IUserService;
import com.serviceprovider.business.module.common.Page;
import com.serviceprovider.business.module.order.model.Order;
import com.serviceprovider.business.module.order.model.OrderSearchCriteria;
import com.serviceprovider.business.module.order.model.OrderSelectFilterForm;
import com.serviceprovider.business.module.order.services.interfaces.IOrderFiltersService;
import com.serviceprovider.business.module.order.services.interfaces.IOrderService;
import com.serviceprovider.business.module.order.valueobjects.OrderFilterConditionVO;
import com.serviceprovider.business.module.order.valueobjects.OrderFilterVO;
import com.serviceprovider.business.module.order.valueobjects.OrderVO;
import com.serviceprovider.business.utility.ApplicationConfigProperties;
import com.serviceprovider.business.utility.RequestConstants;
import com.serviceprovider.business.utility.SecurityContextUser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

//~--- JDK imports ------------------------------------------------------------

import java.text.SimpleDateFormat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

/**
 * This class will handle all the view order related operations.
 * The order view will be changed with logged in user with their privileges.
 *
 * @author mrduongnv@gmail.com
 */
@Controller
public class ViewOrdersController {
    @Autowired
    private ApplicationConfigProperties applicationConfigProperties;
    @Autowired
    private IOrderFiltersService        orderFiltersService;
    @Autowired
    private IOrderService               orderService;
    @Autowired
    private ApplicationConfigProperties properties;
    @Autowired
    private IUserService                userService;

    /**
     * Initialize date formatter used in this forms.
     *
     * @param binder WebDataBinder instance.
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(properties.getDateFormat());

        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    /**
     * This will return all the order details to order view. The data are filtered according to
     * the logged in user role. If role is administrator this will show all the orders if not
     * this will show all the orders belongs to the service provider.
     *
     * @return
     */
    @RequestMapping(
        value  = RequestConstants.OrderRequests.VIEW_ORDERS,
        method = RequestMethod.GET
    )
    public ModelAndView viewOrdersFilter(HttpServletRequest request) {
        ModelAndView        result     = new ModelAndView(RequestConstants.OrderRequests.VIEW_ORDERS_VIEW);
        List<OrderFilterVO> filterList = orderFiltersService.findAllActive();
        Page<Order>         orderList;
        boolean             isAdmin    = SecurityContextUser.isAdmin();
        int                 recordSize = applicationConfigProperties.getRecordSize("view_orders.records.size");

        if ((request.getParameter("recordSize") != null) &&!"0".equals(request.getParameter("recordSize"))) {
            recordSize = Integer.parseInt(request.getParameter("recordSize"));
        }

        int pageNo = 1;

        try {
            pageNo = Integer.parseInt(request.getParameter("pageNo"));
        } catch (NumberFormatException ignored) {}

        String sortOrder = ((request.getParameter("sortOrder") == null)
                            || (request.getParameter("sortOrder").length() == 0))
                           ? "asc"
                           : request.getParameter("sortOrder");
        String sortColumn = ((request.getParameter("sortColumn") == null)
                             || (request.getParameter("sortColumn").length() == 0))
                            ? "order_id"
                            : request.getParameter("sortColumn");

        if (isAdmin) {
            orderList = orderService.findAll(pageNo, recordSize, sortColumn, sortOrder);
        } else {
            orderList = orderService.findOrderByUserId(userService.getUserConnected().getId(), pageNo, recordSize,
                    sortColumn, sortOrder);
        }

        List<OrderVO> orderVoList = new ArrayList<OrderVO>();

        for (Order order : orderList.getPageItems()) {
            OrderVO orderVO = new OrderVO(order);

            orderVO.setProvider(userService.getById(order.getServiceProviderId()));
            orderVoList.add(orderVO);
        }

        result.addObject("orderList", getOrderVOPage(orderVoList, orderList));
        result.addObject("filterList", filterList);
        result.addObject("orderSelectFilterForm", new OrderSelectFilterForm());
        result.addObject("orderSearchCriteria", new OrderSearchCriteria());
        result.addObject("isAdmin", isAdmin);

        return result;
    }

    /**
     * This method will filter orders according to the criteria or given filter values.
     *
     * @param orderSelectFilterForm OrderSelectFilterForm instance
     * @param orderSearchCriteria   OrderSearchCriteria instance
     * @return
     */
    @RequestMapping(
        value  = RequestConstants.OrderRequests.VIEW_ORDERS,
        method = RequestMethod.POST
    )
    public ModelAndView reportSelection(@ModelAttribute OrderSelectFilterForm orderSelectFilterForm,
            @ModelAttribute OrderSearchCriteria orderSearchCriteria, HttpServletRequest request) {
        ModelAndView        result     = new ModelAndView(RequestConstants.OrderRequests.VIEW_ORDERS_VIEW);
        boolean             isAdmin    = SecurityContextUser.isAdmin();
        List<OrderFilterVO> filterList = orderFiltersService.findAll();
        Page<Order>         orderList;
        int                 recordSize = applicationConfigProperties.getRecordSize("view_orders.records.size");

        if ((request.getParameter("recordSize") != null) &&!"0".equals(request.getParameter("recordSize"))) {
            recordSize = Integer.parseInt(request.getParameter("recordSize"));
        }

        int pageNo = 1;

        try {
            pageNo = Integer.parseInt(request.getParameter("pageNo"));
        } catch (NumberFormatException ignored) {}

        String sortOrder = ((request.getParameter("sortOrder") == null)
                            || (request.getParameter("sortOrder").length() == 0))
                           ? "asc"
                           : request.getParameter("sortOrder");
        String sortColumn = ((request.getParameter("sortColumn") == null)
                             || (request.getParameter("sortColumn").length() == 0))
                            ? "order_id"
                            : request.getParameter("sortColumn");

        if (isAdmin) {
            OrderFilterVO                filter = orderFiltersService.getById(orderSelectFilterForm.getFilterId());
            List<OrderFilterConditionVO> list   = filter.getFilterConditionList();

            orderList = orderService.getAllUsingFilter(list, pageNo, recordSize, sortColumn, sortOrder);
        } else {
            orderList = orderService.findOrderBySearchCriteria(orderSearchCriteria, pageNo, recordSize, sortColumn,
                    sortOrder);
        }

        List<OrderVO> orderVoList = new ArrayList<OrderVO>();

        for (Order order : orderList.getPageItems()) {
            OrderVO orderVO = new OrderVO(order);

            orderVO.setProvider(userService.getById(order.getServiceProviderId()));
            orderVoList.add(orderVO);
        }

        result.addObject("orderList", getOrderVOPage(orderVoList, orderList));
        result.addObject("filterList", filterList);
        result.addObject("orderSelectFilterForm", new OrderSelectFilterForm());
        result.addObject("orderSearchCriteria", new OrderSearchCriteria());
        result.addObject("isAdmin", isAdmin);

        return result;
    }

    /**
     * This will redirect to the viewOrdersFilter method. only used for url mapping for the service provider.
     *
     * @return
     */
    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_VIEW_ORDERS,
        method = RequestMethod.GET
    )
    public ModelAndView viewOrderFilterforForSeviceProvider(HttpServletRequest request) {
        return viewOrdersFilter(request);
    }

    /**
     * This will redirect to the viewOrdersFilter method. only used for url mapping for the service provider.
     *
     * @param orderSelectFilterForm OrderSelectFilterForm instance
     * @param orderSearchCriteria   OrderSearchCriteria instance
     * @return
     */
    @RequestMapping(
        value  = RequestConstants.OrderRequests.SP_VIEW_ORDERS,
        method = RequestMethod.POST
    )
    public ModelAndView reportSelectionForSeviceProvider(@ModelAttribute OrderSelectFilterForm orderSelectFilterForm,
            @ModelAttribute OrderSearchCriteria orderSearchCriteria, HttpServletRequest request) {
        return reportSelection(orderSelectFilterForm, orderSearchCriteria, request);
    }

    private Page<OrderVO> getOrderVOPage(List<OrderVO> orderVOs, Page<Order> orderList) {
        Page<OrderVO> pageOrderVO = new Page<OrderVO>();

        pageOrderVO.setPageItems(orderVOs);
        pageOrderVO.setPageNumber(orderList.getPageNumber());
        pageOrderVO.setPagesAvailable(orderList.getPagesAvailable());
        pageOrderVO.setRecordSize(orderList.getRecordSize());
        pageOrderVO.setSortColumn(orderList.getSortColumn());
        pageOrderVO.setSortOrder(orderList.getSortOrder());
        pageOrderVO.setTotalRecords(orderList.getTotalRecords());

        return pageOrderVO;
    }
}



